package com.summer.safe.utils;

import com.alibaba.druid.filter.config.ConfigTools;
import org.apache.commons.lang3.Validate;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;

/**
 * sm3工具类
 */
public class Sm3Utils {
    private static final String ENCODING = "UTF-8";

    public static final int HASH_INTERATIONS = 1024;
    public static final int SALT_SIZE = 8;

    private static SecureRandom random = new SecureRandom();

    static {
        Security.addProvider(new BouncyCastleProvider());
    }



    /**
     * 解密数据库名称
     * @param username
     */
    public static String setUsername(String username) {
        try {
            username = ConfigTools.decrypt(username);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return username;
    }


    /**
     * 解密数据库密码
     * @param password
     */
    public static String setPassword(String password) {
        try {
            password = ConfigTools.decrypt(password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return password;
    }

    /**
     * sm3算法加密
     *
     * @param paramStr 待加密字符串
     * @return
     */
    public static String encrypt(String paramStr) {
        String resultHexString = "";
        try {
            //将字符串转化成byte数组
            byte[] srcData = paramStr.getBytes(ENCODING);

            byte[] salt = generateSalt(SALT_SIZE);

            //调用hash
//            byte[] resultHash = hash(srcData);
            byte[] resultHash = hash(srcData, salt);
            //将返回的hash值转换成16进制字符串
//          resultHexString = ByteUtils.toHexString(resultHash);

            resultHexString = Encodes.encodeHex(salt) + Encodes.encodeHex(resultHash).substring(0,48);

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return resultHexString;
    }

    /**
     * 生成对应的hash值
     *
     * @param srcData
     * @return
     */
    public static byte[] hash(byte[] srcData, byte[] salt) {
        SM3Digest digest = new SM3Digest();
        int str1Length = srcData.length;
        int str2length = salt.length;

        srcData = Arrays.copyOf(srcData, str1Length + str2length);//数组扩容
        System.arraycopy(salt, 0, srcData, str1Length, str2length);

        digest.update(srcData, 0, srcData.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return hash;
    }

    /**
     * 返回长度32 byte数组 生成对应的hash值
     *
     * @param srcData
     * @return
     */
    public static byte[] hash(byte[] srcData) {
        SM3Digest digest = new SM3Digest();
        digest.update(srcData, 0, srcData.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return hash;
    }

    /**
     * 自定义密钥
     * <p>
     * 通过指定密钥进行加密
     *
     * @param key     密钥
     * @param srcData 被加密的byte数组
     * @return
     */
    public static byte[] hmac(byte[] key, byte[] srcData) {
        KeyParameter keyParameter = new KeyParameter(key);
        SM3Digest digest = new SM3Digest();
        HMac hMac = new HMac(digest);
        hMac.init(keyParameter);
        hMac.update(srcData, 0, srcData.length);
        byte[] result = new byte[hMac.getMacSize()];
        hMac.doFinal(result, 0);
        return result;
    }


    /**
     * 判断源数据与加密数据是否一致
     * <p>
     * 通过验证数组和生成的hash数组是否为同一数组，验证2者是否为同一数据
     *
     * @param srcStr       原字符串
     * @param sm3HexString 16进制字符串
     * @return 校验结果
     */
    public static boolean verify(String srcStr, String sm3HexString) {
        boolean flag = false;
        try {
            byte[] srcData = srcStr.getBytes(ENCODING);
            byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString);

            byte[] salt = Encodes.decodeHex(sm3HexString.substring(0, 16));

//            byte[] newHash = hash(srcData);
            byte[] newHash = hash(srcData, salt);
            flag = sm3HexString.equals(Encodes.encodeHex(salt) + Encodes.encodeHex(newHash).substring(0,48));
//            if (Arrays.equals(newHash, sm3Hash))
//                flag = true;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 生成随机的Byte[]作为salt.
     *
     * @param numBytes byte数组的大小
     */
    public static byte[] generateSalt(int numBytes) {
        Validate.isTrue(numBytes > 0, "numBytes argument must be a positive integer (1 or larger)", numBytes);

        byte[] bytes = new byte[numBytes];
        random.nextBytes(bytes);
        return bytes;
    }

    public static void main(String[] args) {
        String pwd = "123456";
        String hex = Sm3Utils.encrypt(pwd);
        System.out.println(hex);

        boolean b = Sm3Utils.verify("123456", hex);
        System.out.println(b);
    }
}
